Uwierzytelnienie i autoryzacja
==============================

Uwierzytelnienie oraz autoryzacja są wymagane dla stron WWW, które powinny mieć 
ograniczony dostęp dla pewnych osób. "Uwierzytelnienie" dotyczy weryfikacji czy ktoś 
jest tym za kogo się podaje. Zazwyczaj używa do tego nazwę użytkownika oraz hasło, 
aczkolwiek może zawierać również inne metody reprezentujące tożsamość, takie jak 
karta inteligentna (mikroprocesorowa), odciski palców itp. "Autoryzacja" jest znajdywaniem 
czy osoba raz zidentyfikowana (np. uwierzytelniona), posiada uprawnienia do posługiwania się 
określonym zasobem. Zazwyczaj determinowane jest to poprzez stwierdzanie, czy ta osoba 
posiada konkretną rolę, która gwarantuje dostęp do zasobu.

Yii posiada wbudowany framework uwierzytelnienia/autoryzacji (auth), który jest
łatwy w użyciu i może być dostosowywany do konkretnych potrzeb.

Centralnym miejscem we frameworku auth w Yii jest predefiniowany *komponent użytkownika aplikacji*
(ang. *user application component*), który jest obiektem implementującym interfejs [IWebUser].
Component użytkownika reprezentuje stałą informację o tożsamości aktualnego użytkownika. 
Możemy uzyskać do niej dostęp w każdym miejscu poprzez użycie `Yii::app()->user`.


Używając komponentu użytkownika możemy sprawdzić czy użytkownik jest zalogowany, 
czy też nie, poprzez [CWebUser::isGuest]; możemy [zalogować|CWebUser::login] lub 
[wylogować|CWebUser::logout] użytkownika; możemy sprawdzić, czy użytkownik może 
wykonywać określone operacje poprzez wywołanie [CWebUser::checkAccess]; oraz możemy 
również otrzymać [unikalny identyfikator|CWebUser::name] oraz inne trwałe informacje 
dotyczące tożsamości użytkownika.

Definiowanie klasy tożsamości
-----------------------------

Jak wspomniano wcześniej, uwierzytelnienie dotyczy sprawdzania tożsamości użytkownika. Typowa implementacja uwierzytelnienia w aplikacji sieciowej zazwyczaj używa kominacji nazwy użytkownika oraz hasła w celu sprawdzenia tożsamości użytkownika. Jednakże, może ona zawierać różne metody a także różne implementacje mogą być wymagane. Aby dostosować się do różnych metod uwierzytelniania, framework auth Yii wprowadza klasę tożsamości.

Główną pracą w definiowaniu klasy tożsamości jest implementacja metody [IUserIdentity::authenticate]. 
Metoda ta jest używana do hermetyzacji szczegółów podejścia do uwierzytelnienia. Klasa tożsamości może również 
deklarować dodatkowe informacje o tożsamości, które muszą trwać podczas sesji użytkownika.

#### Przykład

W przykładzie tym, używamy klasy tożsamości do zademonstrowania podejścia bazodanowego do tematu uwierzytelnienia. Jest to bardzo typowe dla aplikacji sieciowych. Użytkownik wprowadza jego nazwę oraz hasło do formularza logowania, my następnie spradzimy poprawność tych danych używając [rekordu aktywnego](/doc/guide/database.ar), porównując z danymi z tabeli użytkowników. W tym jednym przykładzie, demonstrujemy kilka rzeczy: 

1. Implementację metody `authenticate()` w celu spradzenia poprawności wprowadzonych danych logowania.
2. Nadpisanie metody `CUserIdentity::getId()` w celu zwrócenia właściwości `_id`, gdyż domyślnie implementacja ta zwraca jako ID nazwę użytkownika.
3. Uzyciu metody `setState()` ([CBaseUserIdentity::setState]) w celu zademonstrowania przechowywania pozostałych informacji, które mogą zostać łatwo zwrócone przy kolejnych żądaniach.

~~~
[php]
class UserIdentity extends CUserIdentity
{
	private $_id;
	public function authenticate()
	{
		$record=User::model()->findByAttributes(array('username'=>$this->username));
		if($record===null)
			$this->errorCode=self::ERROR_USERNAME_INVALID;
		else if($record->password!==md5($this->password))
			$this->errorCode=self::ERROR_PASSWORD_INVALID;
		else
		{
			$this->_id=$record->id;
			$this->setState('title', $record->title);
			$this->errorCode=self::ERROR_NONE;
		}
		return !$this->errorCode;
    }

	public function getId()
	{
		return $this->_id;
	}
}
~~~

Kiedy opiszemy logowanie i wylogowywanie w następnych rozdziałach, zobaczymy, że przekazujemy tą klasę tożsamości do metody logowania użytkownika. Pozostałe informacje, które zapisujemy w stanach (poprzez wywołanie [CBaseUserIdentity::setState]) będą przekazane do kalsy [CWebUser], która z kolei zapisze je w nośniku trwałych danych, np. takim jak sesja.
Informacje te mogą być później dostępne jak właściwości [CWebUser]. W naszym przykładzie,  przechowujemy informację o tytule użytkownika poprzez `$this->setState('title', $record->title);`. Gdy już zakończymy proces logowania, możemy uzyskać informację o tytule `title` użytkownika poprzez proste użycie `Yii::app()->user->title`.

W następnym przykładzie sprawdzimy poprawność użytkownika i hasła porównując je 
z tabelą użytkowników w bazie danych przy użyciu [Rekordu Aktywnego](/doc/guide/database.ar). 
Możemy również nadpisać metodę `getId` aby zwracała zmienną `_id`, która jest ustawiana
podczas uwierzytelniania (domyślna implementacja zwróci nazwę użytkownika jako ID). 
Podczas uwierzytelniania zapisujemy otrzymaną informację o tytule `title` w stanie 
o tej samej nazwie poprzez wywołanie metody [CBaseUserIdentity::setState].

> Info|Info: Domyślnie [CWebUser] używa sesji jako trwałego miejsca składowania informacji
o tożsamości użytkownika. Jeśli logowanie z użyciem ciasteczek jest udostępnione 
(poprzez ustawienie wartości [CWebUser::allowAutoLogin] jako true), informacje
o tożsamości użytkownika mogą także zostać zapisane w ciasteczku. Upewnij się, że nie 
zadeklarowałeś ważnych danych (np. hasła) jako wartości trwałej.

Logowanie i wylogowanie
-----------------------

Teraz gdy widzieliśmy przykład tworzenia klasy tożsamości, użyjemy tego aby ułatwić implementację
akcji naszych akcji logowania i wylogowania. Następujący kod demonstruje jak można to uczynić:

~~~
[php]
// logowanie użytkownika za pomocą nazwy użytkownika oraz hasła
$identity=new UserIdentity($username,$password);
if($identity->authenticate())
	Yii::app()->user->login($identity);
else
	echo $identity->errorMessage;
......
// wylogowanie aktualnego użytkownika
Yii::app()->user->logout();
~~~

Tutaj utworzyliśmy nowy obiekt UserIdentity i przekazaliśmy mu dane uwierzytelniające (np. nazwę `$username` i hasło `$password` podane przez użytkownika) do jego konstruktora.  Następnie wołamy po prostu metodę `authenticate()`. Jeśli zakończy się ona sukcesem, przekazujemy informację o tożsamości do metody [CWebUser::login], która przechowa informację o tożsamości w trwałym nośniku danych (domyślnie sesja PHP) w celu zwrócenia ich w następnych żądaniach. Jeśli uwierzytelnianie nie powiedzie się, możemy uzupełnić właściwość `errorMessage` bardziej szczegółowym opisem przyczyny niepowodzenia.

Czy użytkownik został uwierzytelniony czy też nie, można sprawdzić w całej aplikacji poprzez użycie `Yii::app()->user->isGuest`. Jeśli używamy nośników trwałych danych takich jak sesja (domyślnie) i/lub ciasteczek (omówionych później) w celu zapisania informacji o tożsamości, użytkownik może pozostać zalogowany podczas kolejnych żądań. W tym przypadku, gdy nie potrzebujemy klasy UserIdentity oraz całego procesu logowania podczas każdege żądania. Raczej to CWebUser automatycznie zadba o ładowanie informacji o tożsamości użytkownika z nośnika trwałych danych i będzie używał ich do zdeterminowania czy `Yii::app()->user->isGuest` zwraca prawdę lub fałsz.

Logowanie przy użyciu ciasteczek
--------------------------------

Domyślnie, użytkownik będzie wylogowany po pewnym czasie braku aktywności, w zależności
od [konfiguracji sesji](http://www.php.net/manual/en/session.configuration.php).
Aby zmienić to zachowanie, możemy ustawić właściwość komponentu użytkownika 
[allowAutoLogin|CWebUser::allowAutoLogin] jako true oraz przekazać parametr określający 
okres trwania (ang. duration) do metody [CWebUser::login]. Użytkownik pozostanie 
zalogowany w podanym okresie, nawet jeśli zamknie okno swojej przeglądarki. 
Pamiętaj, że funkcjonalność ta wymaga aby przeglądarka użytkownika akceptowała ciasteczka.

~~~
[php]
// Utrzymaj użytkownika zalogowanym przez 7 dni
// upewnij się, że allowAutoLogin jest ustawiona jako true dla komponentu użytkownika
Yii::app()->user->login($identity,3600*24*7);
~~~

Jak wspomnieliśmy powyżej, kiedy logowanie za pomocą ciasteczej jest udostępnione, stany 
zachowane przez [CBaseUserIdentity::setState] będą również zapisane w ciasteczkach. 
Następnym razem, gdy użytkownik zaloguje się, stany te będą odczytane z ciasteczek i staną
się dostępne poprzez `Yii::app()->user`.

Chociaż Yii posiada środki do zabezpieczenia stanów w ciasteczkacj przez zmodyfikowaniem
po stronie kienta, mocno rekomendujemy, by wrażliwe dane nie były przechowywane w stanach.
Zamiast tego, informacje te powinny być odtworzone po stronie serwera poprzez odczytanie ich
z jakiegoś nośnika danych trwałech po stronie serwera (np. z bazy danych).

Ponadto, w wielu poważnych aplikacjach sieciowych, zalecamy używanie następujacej strategii,
w celu rozszerzenia bezpieczeństwa logowania przy użyciu cisteczek.

* Jeśli użytkownik zaloguje się poprzez wypełnienie formualrza logowania, generujemy i zapisujemy 
losowy klucz zarówno w ciasteczku jak i w nośniku po stronie serwera (np. w bazie danych).

* W kolejnych żądaniach, jeśli uwierzytelnianie poprzez ciasteczka zakończy się, porównujemy dwie kopie 
tych losowych kluczy i upewniamy się czy pasują one do siebie przed zalogowaniem użytkownika.

* Jeśli użytkownik zaloguje się ponownie poprzez formularz logowania, klucz powinien zostać przegenerowany.

Używając powyższej strategii, wyeliminujemy możliwość ponownego użycia starego stanu z ciasteczek,
które może posiadać przestarzałe informacje.

W celu zaimplementowanie powyższej strategii, musimy nadpisać następujące 2 metody:

* [CUserIdentity::authenticate()]: to miejsce gdzie rzeczywiste uwierzytelnienie ma miejsce.
Jeśli użytkownik jest uwierzytelniony, powinnniśmy przegenerować losowy klucz i zapisać go
w bazie danych tak jak i w stanie poprzez [CBaseUserIdentity::setState].

* [CWebUser::beforeLogin()]: metoda ta jest wołana gdy użytkownik loguje się.
Powinniśmy sprawdzić czy klucz uzyskany ze stanu zapisanego w ciasteczku jest taki sam jak ten z bazy.

Filtr kontroli dostępu (ang. Access Control Filter)
---------------------


Filtr kontroli dostępu jest wstępnym schematem autoryzacji, który sprawdza, 
czy aktualny użytkownik może wywoływać żądaną przez kontroler akcję. Autoryzacja 
bazuje na nazwie użytkownika, adresie IP klienta oraz type żądania. Jest ona dostarczona 
jako filtr nazwany ["accessControl"|CController::filterAccessControl].

> Tip| Porada: Filtr kontroli dostępu jest wystarczający dla prostych scenariuszy. 
Dla bardziej skomplikowanej kontroli dostępu możesz użyć bazującej na rolach kontroli dostępu 
(RBAC - role-based access control), która zostanie przedstawiona w dalszej części.

Aby kontrolować dostęp do akcji w kontrolerze instalujemy filtr kontroli akcji 
poprzez nadpisanie metody [CController::filters] (zobacz
[filtry](/doc/guide/basics.controller#filter) aby uzyskać więcej informacji dotyczących 
instalowania filtrów).

~~~
[php]
class PostController extends CController
{
	......
	public function filters()
	{
		return array(
			'accessControl',
		);
	}
}
~~~

Powyżej, określiliśmy, że filtr [kontroli dostępu|CController::filterAccessControl] 
powinien być zastosowany dla każdej akcji kontrolera `PostController`. Szczegółowe 
reguły autoryzacji używane przez filtr są zdefiniowane poprzez nadpisanie 
[CController::accessRules] w klasie kontrolera.

~~~
[php]
class PostController extends CController
{
	......
	public function accessRules()
	{
		return array(
			array('deny',
				'actions'=>array('create', 'edit'),
				'users'=>array('?'),
			),
			array('allow',
				'actions'=>array('delete'),
				'roles'=>array('admin'),
			),
			array('deny',
				'actions'=>array('delete'),
				'users'=>array('*'),
			),
		);
	}
}
~~~

Powyższy kod definiuje 3 reguły, każda reprezentowana jest poprzez tablicę. 
Pierwszy element w tablicy to `'allow'` (zezwól) lub `'deny'` (zabroń) a pozostałe
pary nazwa-wartość określają wzorce parametrów reguły. Reguły te odczytujemy następująco:
akcje `create` (utwórz) oraz `edit` (redaguj) nie mogą być wykonywane przez anonimowych 
użytkowników; akcja `delete` (usuń) może zostać wykonywana przez użytkowników posiadających 
rolę `admin`; oraz akcja `delete` nie może być wykonywana przez wszystkich.

Reguły dostępu są sprawdzane jedna po drugiej w kolejności takiej w jakiej zostały 
wyspecyfikowane. Pierwsza reguła która pasuje do naszego wzorca (np. nazwa użytkownika, 
rola, IP klienta, adres) determinują rezultat autoryzacji. Jeśli regułą tą jest `allow` (zezwól)
akcja może zostać wykonana; jeśli jest to reguła `deny` (zabroń), akcja nie może zostać 
wykonana; jeśli żadna z reguł nie pasuje do zawartości, akcja wciąż może być wykonana.

> Tip|Wskazówka: Aby upewnić się, że akcja nie zostanie wykonana dla określonego kontekstu,
> najlepiej jest zawsze określić na końcu zbioru reguł, regułę, która będzie dotyczyła
> wszystkich i która zabroni dostępu do tej akcji, jak następuje:
> ~~~
> [php]
> return array(
>     // ... pozostałe reguły ...
>     // następująca reguła zabrania akcji 'delete' dla wszystkich kontekstów
>     array('deny',
>         'actions'=>'delete',
>     ),
> );
> ~~~
> Powodem istnienia tej reguły jest fakt, że jeśli żadna z reguł nie będzie 
> pasowała do kontekstu, akcja będzie kontynuować przetwarzanie.


Reguła dostępu może pasować do następujących parametrów kontekstowych:

   - [actions|CAccessRule::actions]: określa jakich akcji reguła ta dotyczy. Powinna być to tablica ID akcji. 
   Porównywanie nie uwzględnia wielkości liter. 

   - [users|CAccessRule::users]: określa, których użytkowników reguła ta dotyczy.
   Aktualna [nazwa|CWebUser::name] użytkownika jest używana do sprawdzania. Porównywanie nie uwzględnia wielkości liter. Można 
   tutaj używać 3 znaków specjalnych:

	   - `*`: każdy użytkownik włączając w to użytkowników uwierzytelnionych jak i anonimowych,
	   - `?`: użytkownicy anonimowi,
	   - `@`: użytkownicy uwierzytelnieni.

   - [roles|CAccessRule::roles]: określa, które role pasują do tych reguł.
   Używane w [bazującej na rolach kontroli dostępu](/doc/guide/topics.auth#role-based-access-control), 
   która zostanie opisana w następnej podsekcji. W szczególności, reguła ma zastosowanie
   jeśli metoda [CWebUser::checkAccess] zwróci true dla jednej z ról. Zauważ, że powinieneś,
   głównie używać ról dla reguły `allow` (zezwól), ponieważ z definicji, rola reprezentuje 
   pozwolenie na zrobienie czegoś. Należy również zauważyć, iż mimo tego, że używamy tutaj pojęcia
   `role`, ich wartości mogą być w rzeczywistości dowolnymi jednostkami autoryzacji włączając w to 
   role, zadania oraz operacje.
   
   - [ips|CAccessRule::ips]: określa adres IP klienta dla pasującej reguły.

   - [verbs|CAccessRule::verbs]: określa typ żądania (np.`GET`, `POST`) pasującej reguły. Porównywanie nie uwzględnia wielkości liter.

   - [expression|CAccessRule::expression]: określenia wyrażenie PHP, którego wartość
   określa czy reguła jest pasującą. W wyrażeniach możesz używać zmiennej użytkownika `$user`,
   która referuje do `Yii::app()->user`. 


Zarządzanie wynikami autoryzacji
--------------------------------

Kiedy autoryzacja nie powiedzie się, np. użytkownik nie może wykonać określonej
akcji, jeden z dwóch poniższych scenariuszy może mieć miejsce:

   - jeśli użytkownik nie jest zalogowany i jeśli właściwość [loginUrl|CWebUser::loginUrl]
komponentu użytkownika jest skonfigurowana jako URL strony logowania, przeglądarka
zostanie przekierowana na tą stronę. Zauważ, że domyślnie [loginUrl|CWebUser::loginUrl] 
wskazuje na stronę `site/login`.

   - w przeciwnym przypadku wyjątek HTTP zostanie wyświetlony wraz z kodem błędu 403.

Podczas konfigurowania właściwości [loginUrl|CWebUser::loginUrl] można podać relatywny jak i absolutny URL. Można również przekazać tablicę, która będzie 
używana do wygenerowania URL poprzez wywołanie [CWebApplication::createUrl]. 
Pierwszy element tablicy powinien określać [trasę](/doc/guide/basics.controller#route) 
do akcji logowania kontrolera a pozostałe pary parametrów nazwa-wartość 
są parametrami GET. Na przykład, 

~~~
[php]
array(
	......
	'components'=>array(
		'user'=>array(
		  // to jest aktualna wartość domyślna
			'loginUrl'=>array('site/login'),
		),
	),
)
~~~

Jeśli przeglądarka zostanie przekierowana do strony logowania i logowanie zakończy
się sukcesem, możemy chcieć aby przeglądarka została przekierowana z powrotem
do strony, na której wystąpił błąd autoryzacji. Skąd znamy URL dla tej strony?
Możemy otrzymać tą informację z właściwości [returnUrl|CWebUser::returnUrl] komponentu
użytkownika. Możemy zrobić co następuje aby wykonać przekierowanie:

~~~
[php]
Yii::app()->request->redirect(Yii::app()->user->returnUrl);
~~~

Bazująca na rolach kontrola dostępu (ang. Role-Based Access Control)
--------------------------------------------------------------------

Bazująca na rolach kontrola dostępu (RBAC) dostarcza prostej a zarazem potężnej, 
scentralizowanej kontroli dostępu. Zobacz [artykuł wiki](http://en.wikipedia.org/wiki/Role-based_access_control) 
aby uzyskać więcej szczegółów dotyczących porównania RBAC z innymi, bardziej tradycyjnymi
schematami kontroli dostępu.

Yii implementuje hierarchiczny schemat RBAC przy użyciu komponentu aplikacji 
[authManager|CWebApplication::authManager]. W dalszej części, przedstawimy
główne założenia używane w tym schemacie; później opiszemy jak zdefiniować 
dane autoryzacji; na końcu pokażemy jak użyć te dane aby wykonać sprawdzenie dostępu.

### Przegląd

Podstawowym pojęciem w Yii RBAC jest *jednostka autoryzacji* (ang. authorization item).
Jednostka autoryzacji jest przyzwoleniem na zrobienie czegoś (np. utworzenie nowego 
postu na blogu, zarządzania użytkownikami). W zależności od jej szczegółowości
oraz grupy docelowej, jednostka autoryzacji może zostać sklasyfikowana jako 
*operacje* (ang. operations), *zadania* (ang. tasks) oraz *role* (ang. roles).
Rola zawiera zadania, zadanie zawiera operacje a operacja jest pozwoleniem, które jest
atomowe. Na przykład, możemy posiadać system w którym rola administratora `administrator`
posiada zadanie zarządzania postami `post management` oraz zarządzania użytkownikami `user management`.
Zadanie zarządzania użytkownikami `user management` może zawierać operacje utworzenia użytkownika `create user`,
aktualizacji użytkownika `update user` oraz usunięcia użytkownika `delete user`.
Dla uzyskania większej elastyczności, Yii pozwala również roli na posiadanie 
innych ról lub operacji, zadaniu na posiadanie innych zadań a operacji ma posiadanie innych
operacji.

Jednostka autoryzacji jest jednoznacznie identyfikowana przez swoją nazwę.

Jednostka autoryzacji może być powiązana z *regułą biznesową* (ang. business rule).
Rola biznesowa jest kawałkiem kodu PHP, który będzie wywołany, podczas sprawdzania 
dostępu na poziomie jednostki. Tylko wtedy gdy wywołanie zwróci true, użytkownikowi 
zostanie nadane uprawnienie reprezentowane przez jednostkę. Na przykład, kiedy 
definiujemy operację aktualizowania postu `updatePost`, chcielibyśmy dodać regułę biznesową, 
która sprawdza czy ID użytkownika jest identyczne z ID autora postu, tak że tylko 
autor sam będzie miał pozwolenie na aktualizację postu.


Używając jednostki autoryzacji możemy zbudować *hierarchię autoryzacji* (ang. authorization 
hierarchy). Jednostka `A` jest rodzicem innej jednostki `B` w hierarchii, jeśli 
`A` zawiera `B` (lub powiedzmy `A` dziedziny pozwolenie(a) reprezentowane przez `B`).
Jednostka może posiadać wiele jednostek potomnych ale także może posiadać wiele 
jednostek rodziców. Dlatego też, hierarchia autoryzacji jest grafem częściowo-uporządkowanym
a nie drzewem. W tej hierarchii jednostki ról znajdują się na najwyższych poziomach, 
jednostki operacji na dolnych poziomach, podczas gdy jednostki zadań znajdują się
pomiędzy nimi.

Gdy już mamy hierarchię autoryzacji, możemy przypisać role w tej hierarchii 
do użytkowników aplikacji. Użytkownik raz przypisany do roli, będzie posiadał 
uprawnienia reprezentowane przez tą rolę. Na przykład, jeśli przypiszemy rolę 
administratora `administrator` do użytkownika, będzie on posiadał uprawnienia 
administratora, które zwierają zarządzanie postami `post management` oraz 
zarządzanie użytkownikami `user management` (oraz odpowiadające operacje, takie jak 
tworzenie użytkowników `create user`).

Teraz rozpoczyna się najzabawniejsza część. W akcji kontrolera, możemy sprawdzić, 
czy aktualny użytkownik może usunąć konkretny post. Używając hierarchii RBAC oraz 
przyporządkowań, można to zrobić prosto w następujący sposób:

~~~
[php]
if(Yii::app()->user->checkAccess('deletePost'))
{
	// usuń post
}
~~~

Konfigurowanie menadżera autoryzacji (ang. Configuring Authorization Manager)
-----------------------------------------------------------------------------

Zanim zaczniemy definiować hierarchię autoryzacji oraz sprawdzać dostęp, musimy 
skonfigurować komponent aplikacji [authManager|CWebApplication::authManager].
Yii dostarcza dwa typy menadżerów autoryzacji [CPhpAuthManager] oraz [CDbAuthManager]. 
Pierwszy używa pliku skryptu PHP do przechowywania danych autoryzacji, 
drugi zaś przechowuje dane autoryzacji w bazie. Gdy konfigurujemy komponent aplikacji 
[authManager|CWebApplication::authManager], musimy określić, którą klasę komponentu 
będziemy używać oraz jakie są inicjalne wartości właściwości dla tego komponentu. 
Na przykład,

~~~
[php]
return array(
	'components'=>array(
		'db'=>array(
			'class'=>'CDbConnection',
			'connectionString'=>'sqlite:path/to/file.db',
		),
		'authManager'=>array(
			'class'=>'CDbAuthManager',
			'connectionID'=>'db',
		),
	),
);
~~~

Następnie możemy otrzymać dostęp do komponentu aplikacji 
[authManager|CWebApplication::authManager] używając `Yii::app()->authManager`.

Definiowanie hierarchii autoryzacji (ang. Defining Authorization Hierarchy)
---------------------------------------------------------------------------

Definiowanie hierarchii auoryzacji składa się z 3 kroków: definiowania jednostek
autoryzacji, ustalania relacji pomiędzy jednostkami autoryzacji oraz przypisywania 
ról do użytkowników aplikacji. Komponent aplikacji [authManager|CWebApplication::authManager] 
dostarcza pełnego zestawu API do realizowania tych zadań.

Aby zdefiniować jednostkę autoryzacji, wywołaj jedną z poniższych metod w zależności
od typu jednostki:

   - [CAuthManager::createRole]
   - [CAuthManager::createTask]
   - [CAuthManager::createOperation]


Gdy już mamy zestaw jednostek autoryzacji, możemy wywołać następujące metody aby 
ustalić relacje pomiędzy jednostkami:

   - [CAuthManager::addItemChild]
   - [CAuthManager::removeItemChild]
   - [CAuthItem::addChild]
   - [CAuthItem::removeChild]


Na koniec, możemy wywołać następujące metody aby powiązać jednostki ról 
z indywidualnymi użytkownikami:

   - [CAuthManager::assign]
   - [CAuthManager::revoke]


Poniżej pokazujemy przykład jak zbudować hierarchię autoryzacji za pomocą dostarczonego
API:

~~~
[php]
$auth=Yii::app()->authManager;

$auth->createOperation('createPost','tworzenie postu');
$auth->createOperation('readPost','czytanie postu');
$auth->createOperation('updatePost','aktualizowanie postu');
$auth->createOperation('deletePost','usuwanie postu');

$bizRule='return Yii::app()->user->id==$params["post"]->authID;';
$task=$auth->createTask('updateOwnPost','aktualizowanie postu przez autora',$bizRule);
$task->addChild('updatePost');

$role=$auth->createRole('reader');
$role->addChild('readPost');

$role=$auth->createRole('author');
$role->addChild('reader');
$role->addChild('createPost');
$role->addChild('updateOwnPost');

$role=$auth->createRole('editor');
$role->addChild('reader');
$role->addChild('updatePost');

$role=$auth->createRole('admin');
$role->addChild('editor');
$role->addChild('author');
$role->addChild('deletePost');

$auth->assign('reader','readerA');
$auth->assign('author','authorB');
$auth->assign('editor','editorC');
$auth->assign('admin','adminD');
~~~

Gdy już raz ustaliliśmy hierarchi, komponent [authManager|CWebApplication::authManager] (np.
[CPhpAuthManager], [CDbAuthManager]) załaduje automatycznie pozycje. Dlatego też potrzebujemy
wywołać powyższy kod jedynie raz, a NIE dla każdego żądania. 


> Info|Info: Chociaż powyższy przykad wygląda przydługo oraz nużąco, należy pamiętać, 
że został on stworzony głównie w celach demonstracyjnych. Deweloperzy zazwyczaj 
będą potrzebowali wykonać pewne interfejsy użytkownika, tak, że użytkownicy końcowi, mogą
ich używać do tworzenia hierarchii autoryzacji w sposób bardziej intuicyjny.


Używanie reguł biznesowych
--------------------------

Podczas definiowania hierarchii autoryzacji, możemy powiązać rolę, zadanie lub operację z tak zwaną *regułą biznesową* (ang. business rule). 
Możemy również powiązać regułę biznesową podczas przypisywania roli do użytkownika. Reguła biznesowa jest fragmentem kodu PHP,
który jest wykonywany podczas sprawdzania dostępności. Zwracana przez kod wartość jest używana do określenia, czy rola lub przypisanie ma zastosowanie dla aktualnego 
użytkownika. W powyższym przykładzie, powiązaliśmy regułe bizesową z zadaniem `updateOwnPost` task. W regule biznesowej po prostu sprawdzamy czy ID aktualnego użytkownika 
jest identyczne jak to określone przez ID autora postu. Informacja o poście jest dostarczana przez programistę w tablicy `$params` podczas sprawdzania dostępności.




### Sprawdzanie dostępności

Aby dokonać sprawdzania dostępności, najpierw musimy znać nazwę jednostki autoryzacji.
Na przykład, aby sprawdzić czy aktualny użytkonik może stworzyć post, musimy sprawdzić
czy posiada on uprawnienie reprezentowane przez operację `createPost`. 
Wywołujemy wtedy metodę [CWebUser::checkAccess] aby wykonać sprawdzenie dostępności:

~~~
[php]
if(Yii::app()->user->checkAccess('createPost'))
{
	// utwórz post
}
~~~

Jeśli jednostka autoryzacji jest powiązana z reguła biznesową, która potrzebuje 
dodatkowwch parametrów, możemy je również przekazać. Na przykład, aby sprawdzić 
czy użytkownik może zaktualizwać post, przekażemy dane wiadomości poprzez zmienną `$params`:

~~~
[php]
$params=array('post'=>$post);
if(Yii::app()->user->checkAccess('updateOwnPost',$params))
{
	// zaktualizuj post
}
~~~


### Używanie domyślnych ról

Wiele aplikacji webowych potrzebuje pewnych bardzo specjalnych ról, które będą 
przypisane do każdego lub prawie każdego użytkownika systemu. Na przykład, 
możemy chcież przypisać pewne uprawnienia do wszystkich uwierzytelnionych użytkowników. 
Powoduje to wiele kłopotów z zarządzaniem jeśli bezpośrednio wyspecyfikujemy 
i zachowamy przypisanie tych ról. Możemy wykorzystać 
*domyślne role* (ang. default roles) aby rozwiązać ten problem.

Rola domyślna jest rolą, która jest pośrednio przypisana do każdego użytkownika, 
wliczając w to uwierzytelnionego użytkownika a także gościa. Nie musimy jej 
bezpośrednio przypisywać do użytkownika. Kiedy wywołujemy [CWebUser::checkAccess]
domyślne role będą sprawdzone najpierw jeśli są one przypisane do użytkownika.

Domyślne role muszą zostać zadeklarowane we właściwości [CAuthManager::defaultRoles].
Na przykład, następująca konfiguracja deklaruje dwie role, które będą domyślnymi: 
`authenticated` (uwierzytelniony) oraz `guest` (gość).

~~~
[php]
return array(
	'components'=>array(
		'authManager'=>array(
			'class'=>'CDbAuthManager',
			'defaultRoles'=>array('authenticated', 'guest'),
		),
	),
);
~~~

Ponieważ domyślan rola jest przypisywana do każdego użytkownika, zazwyczaj wymagane 
jest powiązanie z regułą biznesową, która determinuje czu rola naprawdę ma zastosowanie 
dla użytkownika. Na przykład, następujący kod definiuje dwie role `authenticated` 
oraz `guest`, które efektywnie mają zastosowanie dla uwierzytelnionych 
użytkowników oraz gości, odpowiednio: 

~~~
[php]
$bizRule='return !Yii::app()->user->isGuest;';
$auth->createRole('authenticated','uwierzytelniony użytkownik', $bizRule);

$bizRule='return Yii::app()->user->isGuest;';
$auth->createRole('guest','gość', $bizRule);
~~~

<div class="revision">$Id: topics.auth.txt 2890 2011-01-18 15:58:34Z qiang.xue $</div>